// benchmark.cpp - 简单的性能测试程序
#include <iostream>
#include <vector>
#include <cstring>
#include <random>
#include <iomanip>
#include <thread>
#include <atomic>
#include <fstream>
#include <functional>
#include <chrono>
#include "../ConcurrentAlloc/ConcurrentAlloc.h"

using namespace std;
using namespace chrono;

#define MY_MALLOC(size) ConcurrentAlloc(size)
#define MY_FREE(ptr) ConcurrentFree(ptr);

// ===================================================================
// 测试配置
// ===================================================================
const int WARMUP_ITERATIONS = 1000; // 预热次数
const int TEST_ITERATIONS = 10000; //  一轮的测试次数
const int TEST_ROUNDS = 10;        //  总共的测试轮数
const int LOW_LEVEL = 1025;         // 小内存下限
const int HIGH_LEVEL = 8 * 1024;    // 小内存上限
const int THREAD_NUM = 5;           // 多线程个数
const int SINGLE_THREAD = 1;        // 单线程
const size_t DEFAULT_SIZE = 0;      //默认大小标识
const int CNT = 2;                 // 平均值轮数
const vector<size_t> TEST_SIZES = {8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096,8192};

// ===================================================================
// 测试结果结构
// ===================================================================
struct TestResult
{
    string test_name;
    size_t size;
    double my_time_ns;  // 你的实现用时(纳秒)
    double sys_time_ns; // 系统malloc用时(纳秒)
    double improvement; // 性能提升百分比
};

vector<TestResult> all_results;

// ===================================================================
// 范围均匀随机辅助函数
// ===================================================================
// 生成 [min, max] 范围的随机整数
int randomInt(int min, int max)
{
    static std::random_device rd;
    static std::mt19937 gen(rd());
    std::uniform_int_distribution<int> dis(min, max);
    return dis(gen);
}

// ===================================================================
// 计时辅助函数
// ===================================================================

extern void PrintRatio();

clock_t get_time_ns_long(int thread_num, int rounds,int iterations,int malloc_flag,int input_sz)
{
    std::atomic<clock_t> alloc_free_time(0);
    std::vector<std::thread> v(thread_num);

    for (int k = 0; k < thread_num; k++)
    {
        v[k] = std::thread([&]()
        {
            clock_t start_time = clock();
            for(int i = 0;i < rounds;i++)
            {
                std::vector<void*> vptr;
                vptr.reserve(iterations);
                for(int i = 0; i < iterations; i++)
                {
                    int sz = TEST_SIZES.size();
                    int size;
                    if(input_sz > 0)
                        size = input_sz;
                    else
                        size = TEST_SIZES[i % sz];
                    if(!malloc_flag)
                    {
                        void* ptr = MY_MALLOC(size);
                        vptr.push_back(ptr);
                    }
                    else
                    {
                        void* ptr = malloc(size);
                        vptr.push_back(ptr);
                    }
                }
                for(auto& e : vptr)
                {
                    if(!malloc_flag)
                    {
                        MY_FREE(e);
                    }
                    else
                        free(e);
                }  
            }
 
            clock_t end_time = clock();
            alloc_free_time += (end_time - start_time);
            if(!malloc_flag)
                ConcurrentSourcesFree();
            // PrintRatio();
        });
    }

    for(auto& e : v)
        e.join();
    return alloc_free_time;
}

clock_t get_time_ns_short(int thread_num, int rounds,int iterations,int malloc_flag,int input_sz)
{
    std::atomic<clock_t> alloc_free_time(0);
    std::vector<std::thread> v(thread_num);

    for (int k = 0; k < thread_num; k++)
    {
        v[k] = std::thread([&]()
        {
            clock_t start_time = clock();
            for(int i = 0;i < rounds;i++)
            {;
                for(int i = 0; i < iterations; i++)
                {
                    int sz = TEST_SIZES.size();
                    int size;
                    if(input_sz > 0)
                        size = input_sz;
                    else
                        size = TEST_SIZES[i % sz];
                    if(!malloc_flag)
                    {
                        void* ptr = MY_MALLOC(size);
                        MY_FREE(ptr);
                    }
                    else
                    {
                        void* ptr = malloc(size);
                        free(ptr);
                    }
                }
            }
 
            clock_t end_time = clock();
            alloc_free_time += (end_time - start_time);
            if(!malloc_flag)
                ConcurrentSourcesFree();
            // PrintRatio();
        });
    }

    for(auto& e : v)
        e.join();
    return alloc_free_time;
}


//flag:0 短生命周期
//flag:1 长生命周期
clock_t get_time_ns(size_t thread_num,size_t rounds,size_t iterations,size_t input_size,int malloc_flag,int life_flag)
{
    if(life_flag)
        return get_time_ns_long(thread_num,rounds,iterations,malloc_flag,input_size);
    else
        return get_time_ns_short(thread_num,rounds,iterations,malloc_flag,input_size);
}

// ===================================================================
// 测试1: 单一线程和五个线程
// 小内存:1kb~8kb,这个范围内随机数生成
// 高频次:每个线程100000次
// 短生命周期:申请即释放
// ===================================================================
void test_thread(int thread_num,size_t input_size,size_t test_rounds,size_t test_iterations,int cnt)
{
    // cout << "Testing single allocation (size=" << size << " bytes)..." << endl;

    // 预热
    for (int i = 0; i < WARMUP_ITERATIONS; i++)
    {
        int size = randomInt(LOW_LEVEL, HIGH_LEVEL);
        void *ptr = MY_MALLOC(size);
        MY_FREE(ptr);
    }
    
    double improvement = 0;
    double my_time = 0;
    double sys_time = 0;
    for(int i = 0;i < cnt;i++)
    {
        // 测试你的实现
        my_time += get_time_ns(thread_num,test_rounds,test_iterations,input_size,0,1);

        // 测试系统malloc
        sys_time += get_time_ns(thread_num,test_rounds,test_iterations,input_size,1,1);
    }
    my_time /= cnt;
    sys_time /= cnt;
    improvement = (sys_time - my_time) / sys_time * 100;

    std::string name = "different thread_" + std::to_string(thread_num);

    TestResult result = {
        name,
        0,
        my_time,
        sys_time,
        improvement};
    all_results.push_back(result);

    cout << "  MyMalloc: " << fixed << setprecision(2) << my_time << " ns" << endl;
    cout << "  System:   " << fixed << setprecision(2) << sys_time << " ns" << endl;
    cout << "  Improvement: " << fixed << setprecision(1) << improvement << "%" << endl;
    cout << endl;
}

// ===================================================================
// 测试2: 测试小内存分配
// 小内存:128bytes
// ===================================================================
void test_memory_allocation(int thread_num,size_t input_size,size_t test_rounds,size_t test_iterations,int cnt)
{
    std::cout << "Testing memory allocation:" << input_size << std::endl;

    double improvement = 0;
    double my_time = 0;
    double sys_time = 0;
    for(int i = 0;i < cnt;i++)
    {
        // 测试你的实现
        my_time += get_time_ns(thread_num,test_rounds,test_iterations,input_size,0,1);

        // 测试系统malloc
        sys_time += get_time_ns(thread_num,test_rounds,test_iterations,input_size,1,1);
    }
    my_time /= cnt;
    sys_time /= cnt;
    improvement = (sys_time - my_time) / sys_time * 100;

    TestResult result = {
        "different memory allocation",
        input_size,
        my_time,
        sys_time,
        improvement};
    all_results.push_back(result);

    cout << "  MyMalloc: " << fixed << setprecision(0) << my_time << " ns" << endl;
    cout << "  System:   " << fixed << setprecision(0) << sys_time << " ns" << endl;
    cout << "  Improvement: " << fixed << setprecision(1) << improvement << "%" << endl;
    cout << endl;
}

// ===================================================================
// 测试3: 频次测试
// 低频次:每个线程1轮,每轮100次
// 高频次:每个线程10论,每轮10000次
// ===================================================================
void test_frequency(int thread_num,size_t input_size,size_t test_rounds,size_t test_iterations,int cnt)
{
    std::cout << "Testing frequency:" << test_rounds * test_iterations << std::endl;
    
    double improvement = 0;
    double my_time = 0;
    double sys_time = 0;
    for(int i = 0;i < cnt;i++)
    {
        // 测试你的实现
        my_time += get_time_ns(thread_num,test_rounds,test_iterations,input_size,0,1);

        // 测试系统malloc
        sys_time += get_time_ns(thread_num,test_rounds,test_iterations,input_size,1,1);
    }
    my_time /= cnt;
    sys_time /= cnt;
    improvement = (sys_time - my_time) / sys_time * 100;

    std::string name = "different frequency_" + std::to_string(test_rounds * test_iterations);


    TestResult result = {
        name,
        0, // 混合大小
        my_time,
        sys_time,
        improvement};
    all_results.push_back(result);

    cout << "  MyMalloc: " << fixed << setprecision(0) << my_time << " ns" << endl;
    cout << "  System:   " << fixed << setprecision(0) << sys_time << " ns" << endl;
    cout << "  Improvement: " << fixed << setprecision(1) << improvement << "%" << endl;
    cout << endl;
}

// ===================================================================
// 测试4: 不同生命周期对比
// 短生命周期:申请即释放
// 长生命周期:统一申请,统一释放
// ===================================================================
void test_life(int thread_num,size_t input_size,size_t test_rounds,size_t test_iterations,int cnt)
{
    std::string life = "different life period";
    std::cout << "Testing life:" << life << std::endl;
    double improvement = 0;
    double my_time_short = 0;
    double my_time_long = 0;
    for(int i = 0;i < cnt;i++)
    {
        // 测试你的实现
        my_time_short += get_time_ns(thread_num,test_rounds,test_iterations,input_size,0,0);

        // 测试系统malloc
        my_time_long += get_time_ns(thread_num,test_rounds,test_iterations,input_size,1,1);
    }
    my_time_short /= cnt;
    my_time_long /= cnt;
    improvement = (my_time_long - my_time_short) / my_time_long * 100;

    // life += " attention:here,system malloc stands for my malloc(long)";
    TestResult result = {
        life,
        0,
        my_time_short,
        my_time_long,
        improvement};
    all_results.push_back(result);

    cout << "  MyMalloc: " << fixed << setprecision(0) << my_time_short << " ns" << endl;
    cout << "  System:   " << fixed << setprecision(0) << my_time_long << " ns" << endl;
    cout << "  Improvement: " << fixed << setprecision(1) << improvement << "%" << endl;
    cout << endl;
}

// ===================================================================
// 生成测试报告
// ===================================================================
void generate_report()
{
    // 生成Markdown格式的报告
    ofstream report("benchmark_report.md");

    report << "# TCMalloc Performance Benchmark Report\n\n";
    report << "**Test Date**: " << __DATE__ << " " << __TIME__ << "\n\n";

    report << "## Test Environment\n";
    report << "- Compiler: G++\n";
    report << "- Test Iterations: " << TEST_ITERATIONS << "\n\n";

    report << "## Performance Results\n\n";
    report << "| Test Case | Size (bytes) | MyMalloc | System Malloc | Improvement |\n";
    report << "|-----------|-------------|----------|---------------|-------------|\n";

    for (const auto &result : all_results)
    {
        report << "| " << result.test_name << " | ";
        if (result.size > 0)
        {
            report << result.size << " | ";
        }
        else
        {
            report << "Mixed | ";
        }

        // 格式化时间显示
        if (result.my_time_ns < 1000)
        {
            report << fixed << setprecision(1) << result.my_time_ns << " ns | ";
        }
        else if (result.my_time_ns < 1000000)
        {
            report << fixed << setprecision(1) << result.my_time_ns / 1000 << " μs | ";
        }
        else
        {
            report << fixed << setprecision(1) << result.my_time_ns / 1000000 << " ms | ";
        }

        if (result.sys_time_ns < 1000)
        {
            report << fixed << setprecision(1) << result.sys_time_ns << " ns | ";
        }
        else if (result.sys_time_ns < 1000000)
        {
            report << fixed << setprecision(1) << result.sys_time_ns / 1000 << " μs | ";
        }
        else
        {
            report << fixed << setprecision(1) << result.sys_time_ns / 1000000 << " ms | ";
        }

        if (result.improvement > 0)
        {
            report << "**+" << fixed << setprecision(1) << result.improvement << "%** |\n";
        }
        else
        {
            report << fixed << setprecision(1) << result.improvement << "% |\n";
        }
    }

    report << "\n## Summary\n\n";

    // double avg_improvement = 0;
    // int count = 0;
    // for (const auto &result : all_results)
    // {
    //     if (result.test_name.find("Single") != string::npos)
    //     {
    //         avg_improvement += result.improvement;
    //         count++;
    //     }
    // }
    // avg_improvement /= count;

    // report << "- **Average Performance Improvement**: " << fixed << setprecision(1)
    //        << avg_improvement << "%\n";
    // report << "- **Best Case**: Single allocation for small objects\n";
    report << "- **different thread performance**:better than system malloc\n";
    report << "- **small memory performance**:better than system malloc\n";
    report << "- **big memory performance**:worse than system malloc\n";
    report << "- **different life period performance**: better in short life than long life\n";

    report.close();

    cout << "\n===== Report generated: benchmark_report.md =====" << endl;
}

// 应该如何在场景化的测试需求下,设计自身tcmalloc的测试用例,使得能够展现出自身实现tcmalloc优于malloc的地方
// tcmalloc:多线程,小内存,高频次,短生命周期

// 测试控制:控制其它关键因素在最佳,对其中一个因素进行好与坏的比较

// 第一组对比:单个线程与五个线程
int main()
{
    cout << "========================================" << endl;
    cout << "    TCMalloc Performance Benchmark     " << endl;
    cout << "========================================" << endl;
    cout << endl;

    // 1. 不同线程数对比
    cout << ">>> Test 1: Different Thread Number Performance\n"
         << endl;
    cout << "test 5 threads:" << endl;
    test_thread(THREAD_NUM,DEFAULT_SIZE,TEST_ROUNDS,TEST_ITERATIONS,CNT);
    std::cout << "test 1 threads" << std::endl;
    test_thread(SINGLE_THREAD,DEFAULT_SIZE,TEST_ROUNDS,TEST_ITERATIONS,CNT);
    std::cout << std::endl;

    // 2. 不同大小内存对比
    cout << ">>> Test 2: Diffrent Memory Allocation Performance\n"
         << endl;
    
    std::cout << "test small memory" << std::endl;
    test_memory_allocation(THREAD_NUM,2 * 1024,TEST_ROUNDS,TEST_ITERATIONS,CNT);
    std::cout << "test big memory" << std::endl;
    test_memory_allocation(THREAD_NUM,512 * 1024,10,10,CNT);
    std::cout << std::endl;
    
    // 3. 不同频次对比
    cout << ">>> Test 3: Random Size Allocation\n"
         << endl;
    std::cout << "test high frequency" << std::endl;
    test_frequency(THREAD_NUM,DEFAULT_SIZE,TEST_ROUNDS,TEST_ITERATIONS,CNT);
    std::cout << "test low frequency" << std::endl;
    test_frequency(THREAD_NUM,DEFAULT_SIZE,1,1000,CNT);

    std::cout << std::endl;


    // 4. tcmalloc自身长短生命周期区别
    cout << ">>> Test 4: Different Life Period\n"
         << endl;
    test_life(THREAD_NUM,DEFAULT_SIZE,TEST_ROUNDS,TEST_ITERATIONS,CNT);
    std::cout << std::endl;

    // 生成报告
    generate_report();

    cout << "\n========================================" << endl;
    cout << "         Benchmark Complete!            " << endl;
    cout << "========================================" << endl;

    return 0;
}